$ProviderDir = Get-ScriptDir
. "$ProviderDir\AssureDBFramework.ps1"
. "$ProviderDir\ShouldExecutePatch.PS1"
. "$ProviderDir\MarkPatchAsExecuted.PS1"
. "$ProviderDir\ExecuteBatch.PS1"
. "$ProviderDir\XMLDataLoad.PS1"
. "$ProviderDir\GetAllExecutedPatches.PS1"

$DBDeploySqlServerProviderClass = New-PSClass DBDeploySqlServerProvider -inherit $BaseDBDeployProviderClass {
	note -private PSConnection
	note -private ShouldExecutePatch
	note -private MarkPatchAsExecuted
	note -private ExecuteBatch
	note -private CumulativeErrors
	
	Constructor {
		$SchemaDir = $Args[0]

		[system.IO.FileInfo] $configFile = $Args[1]
		$ProviderParms = $Args[2]

		base $SchemaDir $configFile.FullName 

		try {
			$private.PSConnection = $PSSqlConnectionClass.New($ProviderParms)
		} -catch {
			if (([string]$ProviderParms[2]) -eq "" )
			{
				Log-Error ("Unable to connect to Catalog '{1}' on Server '{0}' using Windows Authentication" -f $ProviderParms[0],$ProviderParms[1])
			}
			else
			{
				Log-Error ("Unable to connect to Catalog '{1}' on Server '{0}' using user '{2}'" -f $ProviderParms[0],$ProviderParms[1],$ProviderParms[2])
			}
			exit
		} 

		$private.PSConnection = $PSSqlConnectionClass.New( $ProviderParms )

		$private.ShouldExecutePatch  = $ShouldExecutePatchClass.New( $private.PSConnection )
		$private.MarkPatchAsExecuted = $MarkPatchAsExecutedClass.New( $private.PSConnection, $WhatIf )
		$private.ExecuteBatch = $ExecuteBatchClass.New( $private.PSConnection, $WhatIf )
		
		$this.AddPatchGroupExecutor('SqlFile',$this.ExecutePatchGroup_SQL.Script)
		$this.AddPatchGroupExecutor('GroupedXMLLoad',$this.ExecutePatchGroup_GroupedXMLLoad.Script)
		
		$this.AddScriptExecutor('SQL',$this.ExecuteBatch.Script)
	}

	method -override ProcessPatches {
		$Manifest = $Args[0]
		
		$AssureDB = $AssureDbFrameworkClass.New( $private.PSConnection )
		$AssureDB.Execute()

		Invoke-BaseClassMethod ProcessPatches ([array]$Manifest)
	}

	method -override GetExecutedPathes {
		($GetAllExecutedPatchesClass.New($private.PSConnection)).Execute()
	}
	
	method -override ShouldPatchExecute {
		$PatchFile = $Args[0]
		$SourceCheckSum = $Args[1]
		if ($this.Force) {return $TRUE}
		$private.ShouldExecutePatch.Execute( $PatchFile, $SourceCheckSum)
	}

	method -override MarkPatchAsExecuted {
		$PatchFile = $Args[0]
		$SourceCheckSum = $Args[1]
		$private.MarkPatchAsExecuted.Execute( $PatchFile, $SourceCheckSum)
	}
	
	method -override BeforeItemGroup {
		$PatchGroup = $Args[0]
	}

	method -override ExecuteFileHandler {
		$Handler = $Args[0]
		$file = $Args[1]
		switch ($Handler)
		{
			'ParsedSQL'
				{
					$patchContent = Get-Content $file
					$this.Execute_ParsedSQL( $patchContent )						
				}
		}
	}
	
	method Execute_ParsedSQL {
		Log-Message -level verbose "Execute SQL"
		$this.ExecuteBatch( $Args[0] )						
	}
	
	method ExecutePatchGroup_SQL {
		$PatchMatches = $Args[0]
		$patchMatch.ExecuteHandler("BeforeAll",$this)
		$private.CumulativeErrors = @()
		foreach ($patchMatch in $PatchMatches)
		{
			trap {
				Log-Error "Error while processing $($patchMatch.FileName)"
				Log-Error $_
				if ([string]$patchMatch.FileHandler.ProcessAllOnError -eq 'true')
				{
					$private.CumulativeErrors += $($patchMatch.FileName)
					Log-Error "ProcessAllOnError is enabled.  Continue with PatchGroup"
					continue
				}
				else
				{
					Throw "Error while processing $($patchMatch.FileName): $_"
				}
			}
			$patchMatch.ExecuteHandler("BeforeEach",$this)
			if ($whatif)
			{
				Log-Warning "WhatIf: Executing $($PatchMatch.manifest.Path)"
			}
			else
			{
				Log-Message "Executing $($PatchMatch.manifest.Path)"
			}
			
			try {
				$patchContent = Get-Content $patchMatch.fullFilename.FullName
				$patchMatch.ExecuteValidators( $patchContent )
				
				$this.ExecuteBatch( $patchContent, $patchMatch.FileHandler.CommandTimeout )						

				$this.MarkPatchAsExecuted($patchMatch.manifest.Path,$patchMatch.manifest.SourceCheckSum)
			} -finally {
				$patchMatch.ExecuteHandler("AfterEach",$this)
			}
		}
		if ($private.CumulativeErrors.Count -gt 0)
		{
			Log-Error "$($private.CumulativeErrors.Count) error(s) while processing PatchGroup"
			$private.CumulativeErrors | %{Log-Error "     $_"}
			Throw "Error $($private.CumulativeErrors.Count) while processing PatchGroup"
		}
		$patchMatch.ExecuteHandler("AfterAll",$this)
	}
	
	method ExecutePatchGroup_GroupedXMLLoad {
		$PatchMatches = $Args[0]

		if (! $WhatIf)
		{
  		$PatchMatches[0].ExecuteHandler("BeforeAll",$this)

			$XMLDataLoad = $XMLDataLoadClass.New($private.PSConnection, $WhatIf)
			
			$XMLDataLoad.Setup()
			
			foreach ($PatchMatch in $PatchMatches) 
			{
				$XMLDataLoad.DisableFKs($PatchMatch.Matches['schema'],$PatchMatch.Matches['table'])
			}

			foreach ($PatchMatch in $PatchMatches) 
			{
				$schema = $PatchMatch.Matches['schema']
				$table = $PatchMatch.Matches['table']
				$DataFile = $PatchMatch.fullFilename.FullName
				Log-Message "Loading   $($PatchMatch.manifest.Path)"
				$XMLDataLoad.LoadTable($schema, $table, $DataFile )
				
				$this.MarkPatchAsExecuted($patchMatch.manifest.Path,$patchMatch.manifest.SourceCheckSum)
			}
			
			foreach ($PatchMatch in $PatchMatches) 
			{
				$XMLDataLoad.EnableFKs($PatchMatch.Matches['schema'],$PatchMatch.Matches['table'])
			}

			$XMLDataLoad.Cleanup()

			$PatchMatches[0].ExecuteHandler("AfterAll",$this)
		}
		else
		{
			foreach ($PatchMatch in $PatchMatches) 
			{
				$schema = $PatchMatch.Matches['schema']
				$table = $PatchMatch.Matches['table']
				$DataFile = $PatchMatch.fullFilename.FullName
				Log-Warning "WhatIf: Load   $($PatchMatch.manifest.Path)"
			}
		}
	}
	
	method -override ExecuteBatch {
		Log-Warning -Kind Message -Level Verbose "=============================================================================="
		$sql = $Args[0]
		$CommandTimeout = $Args[1]
		if ($sql.count -gt 0)
		{
			foreach ($line in $sql)
			{
				Log-Message -Level Verbose $line
			}
		}
		else
		{
			Log-Message -Level Verbose $sql
		}
		Log-Message -Level Verbose "Timeout $CommandTimeout"
		#$sql | Log-Message -Level Verbose $_
		$private.ExecuteBatch.Execute($sql, $CommandTimeout)
	}
}
